package handler

import (
	"context"
	"encoding/json"
	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	. "service/goods_srv/global"
	"service/goods_srv/model"
	"service/goods_srv/proto"
)

// 创建商品分类
func (g *GoodsServer) CreateCategory(c context.Context, r *proto.CategoryInfoRequest) (*proto.CategoryInfoResponse, error) {
	category := new(model.Category)
	result := DB.Where(&model.Category{Name: r.Name}).First(category)
	if result.RowsAffected == 1 {
		return nil, status.Errorf(codes.AlreadyExists, "商品分类已存在")
	}

	category = &model.Category{
		Name:             r.Name,
		ParentCategoryID: r.ParentCategory,
		Level:            r.Level,
		IsTab:            r.IsTab,
	}
	result = DB.Create(category)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &proto.CategoryInfoResponse{
		Id:             category.ID,
		Name:           category.Name,
		ParentCategory: category.ParentCategoryID,
		Level:          category.Level,
		IsTab:          category.IsTab,
	}, nil
}

// 获取全部分类列表（含层级关系）
func (g *GoodsServer) GetAllCategorysList(context.Context, *emptypb.Empty) (*proto.CategoryListResponse, error) {
	var categorys []*model.Category
	// 如果使用Preload("SubCategory")，则只会显示到二级分类。
	// preload(预加载)的方式会造成数据库的压力，如果将全部分类一次性读取出来再在内存中对其进行组装会更好一些
	result := DB.Where(&model.Category{Level: 1}).Preload("SubCategory.SubCategory").Find(&categorys)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	b, _ := json.Marshal(&categorys)
	return &proto.CategoryListResponse{JsonData: string(b)}, nil
}

// 获取次级分类
func (g *GoodsServer) GetSubCategory(c context.Context, r *proto.CategoryListRequest) (*proto.SubCategoryListResponse, error) {
	category := new(model.Category)
	category.ID = r.Id
	result := DB.Where(category).First(category)
	if result.RowsAffected != 1 {
		return nil, status.Errorf(codes.AlreadyExists, "商品分类不存在")
	}
	categoryInfoResponse := &proto.CategoryInfoResponse{
		Id:             category.ID,
		Name:           category.Name,
		ParentCategory: category.ParentCategoryID,
		Level:          category.Level,
		IsTab:          category.IsTab,
	}

	subCategories := make([]*model.Category, 0)
	result = DB.Where(&model.Category{ParentCategoryID: r.Id}).Find(&subCategories)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	resSubCategories := make([]*proto.CategoryInfoResponse, 0)
	for _, v := range subCategories {
		resSubCategories = append(resSubCategories, &proto.CategoryInfoResponse{
			Id:             v.ID,
			Name:           v.Name,
			ParentCategory: v.ParentCategoryID,
			Level:          v.Level,
			IsTab:          v.IsTab,
		})
	}

	return &proto.SubCategoryListResponse{
		Total:        int32(len(subCategories)),
		Info:         categoryInfoResponse,
		SubCategorys: resSubCategories,
	}, nil
}

// 删除商品分类
func (g *GoodsServer) DeleteCategory(c context.Context, r *proto.DeleteCategoryRequest) (*emptypb.Empty, error) {
	category := new(model.Category)
	category.ID = r.Id

	result := DB.Where(category).First(category)
	if result.RowsAffected != 1 {
		return nil, status.Errorf(codes.NotFound, "商品分类不存在")
	}

	result = DB.Delete(&category)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// 更新商品分类
func (g *GoodsServer) UpdateCategory(c context.Context, r *proto.CategoryInfoRequest) (*emptypb.Empty, error) {
	category := new(model.Category)
	category.ID = r.Id

	result := DB.Where(category).First(category)
	if result.RowsAffected != 1 {
		return nil, status.Errorf(codes.NotFound, "商品分类不存在")
	}

	var isTab int32
	if r.IsTab {
		isTab = 1
	}
	// 请求参数中包含零值字段也要更新
	result = DB.Model(category).Updates(map[string]interface{}{
		"name":               r.Name,
		"parent_category_id": r.ParentCategory,
		"level":              r.Level,
		"is_tab":             isTab,
	})
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}
